﻿#include <learn/ais/ais_object.h>

using namespace xi;
using namespace xi::ais;

AIS_Object::Status AIS_Object::status() const
{
    return m_status;
}

AIS_Object::ShadeMode AIS_Object::shade_mode() const
{
    return m_shadeMode;
}

std::shared_ptr<AIS_Renderer> AIS_Object::renderer() const
{
    return m_renderer;
}

void AIS_Object::set_status(Status status)
{
    m_status = status;
}

void AIS_Object::set_shade_mode(ShadeMode mode)
{
    m_shadeMode = mode;
}

void AIS_Object::set_parent(AIS_Object *parent)
{
    m_parent = parent;
}

void AIS_Object::add_child(std::shared_ptr<AIS_Object> child)
{
    m_children.push_back(child);
    child->set_parent(this);
}

void AIS_Object::handle_msg(std::shared_ptr<AIS_Msg> msg)
{
    // 先让子节点处理消息，再通知自己
    for (auto child : m_children)
        child->handle_msg(msg);
    msg->accept(this);
}

void AIS_Object::visit(AIS_InitMsg *msg)
{
    // do nothing by default
}

void AIS_Object::visit(AIS_UpdateMsg *msg)
{
    if (m_renderer)
        m_renderer->update(this);
}

void AIS_Object::visit(AIS_PaintMsg *msg)
{
    if (m_renderer && m_status != Status::Hidden)
        m_renderer->draw(this);
}

void AIS_Object::visit(AIS_ShowMsg *msg)
{
    if (msg->show)
        m_status = Status::Normal;
    else
        m_status = Status::Hidden;
}

void AIS_Object::visit(AIS_MoveMsg *msg)
{
    // 如果存在父节点，则通知其更新，由于消息传递，不需要再通知自己
    if (m_parent)
        m_parent->handle_msg(std::make_shared<AIS_UpdateMsg>());
    else
        handle_msg(std::make_shared<AIS_UpdateMsg>());
}

void AIS_Object::visit(AIS_MouseMsg *msg)
{
    // 隐藏则不处理鼠标消息
    if (m_status == Status::Hidden || m_collisionFunc == nullptr)
        return;

    switch (msg->status)
    {
    case AIS_MouseMsg::Press: {
        auto showMsg = std::make_shared<AIS_ShowMsg>();
        // 由于子节点先处理 Mouse 消息，如果坐标轴被选中，当前节点会接收到 Show 消息，状态变为 Normal
        // 从而不会处理第一个分支导致坐标轴隐藏
        if (m_status == Status::Pressed)
        {
            m_status = Status::Normal;
            showMsg->show = false;
            for (auto &child : m_children)
                child->handle_msg(showMsg);
        }
        else if (m_collisionFunc(msg))
        {
            showMsg->show = true;
            if (m_parent)
                m_parent->handle_msg(showMsg);
            else
            {
                for (auto &child : m_children)
                    child->handle_msg(showMsg);
            }
        }
        break;
    }
    case AIS_MouseMsg::Move: {
        if (m_status == Status::Normal || m_status == Status::Hovered)
        {
            m_collisionFunc(msg);
            m_status = Status::Normal;
        }
        break;
    }
    case AIS_MouseMsg::Release: {
        break;
    }
    }
}

void AIS_Object::visit(AIS_DestroyMsg *msg)
{
    m_status = Status::Dead;
}